鐵人賽終於要過一半了,今天要來介紹 Go 的特色之一 -- Goroutines。
那麼話不多說,我們就進入正題吧 ─=≡Σ(((っ゚∀゚)っ
事前提要:必須先瞭解 thread 是什麼!
Goroutines 是由 Go runtime 管理的輕量 thread。
剛剛有提到,他能夠讓程式「同步」執行,但事實上 concurrency(併發)並不是真的同步,而是透過 thread 共享訊息,並且將資源分段處理不同的事情。
簡單的說,就是時間管理大師的概念,在一定的時間內把所有事情給處理完成。
如果對昨天的文章還有印象就會知道 Goroutines 的起手式,就是 go
!
go f(x, y, z)
有了 go
做為起手式後,f
函式因此能跑在另一個 Goroutine 上。
咦,為什麼會說跑在「另一個」Goroutine 呢?
因為 Go 的程式裡會有一個主要的 main goroutine,而這東西就是我們每次都會用到的 main
函式,每當 main
函式執行完成後,就會強制把所有的 gorountine 給關閉掉。
不太了解為什麼嗎?讓我們來 try try see!
package main
import (
"fmt"
)
func say(s string) {
for i := 0; i < 5; i++ {
fmt.Println(s)
}
}
func main() {
go say("world")
go say("hello")
}
這時候應該會發現毫無反應,這是因為現在這個狀態總共開了 3 個 gorountine:main
、 say("world")
、 say("hello")
,每個 goroutine 會乖乖排隊等待被執行,但 main
執行完後根本還沒輪到剩下的兩個,就強制關閉了所有的 goroutine。
要解決這個問題,就需要阻塞住 goroutine,這樣原本在運作的 A goroutine 忽然閒下來了,時間管理大師就能夠趕快再去 B goroutine 處理事情。
有三種方式能夠處理這問題:
time.Sleep()
sync.WaitGroup
// time.Sleep()
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
fmt.Println(s)
}
}
func main() {
go say("world")
go say("hello")
time.Sleep(100 * time.Millisecond)
}
// sync.WaitGroup
package main
import (
"fmt"
"sync"
"time"
)
func say(s string, wg *sync.WaitGroup) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
wg.Done()
}
func main() {
wg := new(sync.WaitGroup)
wg.Add(2)
go say("world", wg)
go say("hello", wg)
wg.Wait()
}
至於 channel 怎麼使用,就交給明天的文章了
有任何問題歡迎與我告知 :)
本篇文章同步更新於我的部落格